//
// Created by Crestimes on 2024/11/15.
//

#include "Parser.h"

#include <queue>
#include <utility>
#include <iostream>

#include "global.h"

Parser::Parser(const vector<Production>& productions,
               const vector<map<string, string>>& lrTable,
               const set<string>& allEndCharNames,
               const vector<GNode>& tokens) {
    this->productions = productions;
    this->lrTable = lrTable;
    this->allEndCharNames = allEndCharNames;
    this->tokens = tokens;
}


void printTrace(stack<GNode> nodeStack, stack<int> stateStack, ostream& out) {
    vector<int> v;
    while (!stateStack.empty()) {
        v.push_back(stateStack.top());
        stateStack.pop();
    }
    out << "stateStack: [";
    while (!v.empty()) {
        out << v.back() << ", ";
        v.pop_back();
    }
    out << endl;
    vector<GNode> ve;
    while (!nodeStack.empty()) {
        ve.push_back(nodeStack.top());
        nodeStack.pop();
    }
    out << "nodeStack: [";
    while (!ve.empty()) {
        out << ve.back().name << ", ";
        ve.pop_back();
    }
    out << endl << endl;
}

void Parser::parse() {
    stack<GNode> nodeStack; // 语法树节点栈
    stack<int> stateStack; // 状态栈
    // 初始状态为0
    stateStack.push(0);
    for (size_t i = 0; i < tokens.size(); i++) {
        int state = stateStack.top(); // 当前状态，作为分析表的行数
        string item = tokens[i].name; // 当前字符，使用映射获取对应的操作
        if (lrTable[state].count(item)) {
            string opr = lrTable[state][item];
            cout << state << " --- " << item << " ---> " << opr << endl;
            printTrace(nodeStack, stateStack, cout);
            int index = stoi(opr.substr(1, opr.size() - 1));
            Production production;
            GNode node;
            switch (opr[0]) {
                case 's':
                    // 移进项
                    nodeStack.push(tokens[i]);
                    stateStack.push(index);
                    break;
                case 'r':
                    // 规约项
                    i--; // 本次的token没有使用，需要回退一次，下次循环再处理该token
                // 获取对应的文法语句
                    production = productions[index];
                // 弹出等量的状态数和语法节点数，同时需要构建语法树
                    node = buildGNode(production, stateStack, nodeStack);
                // 通过状态栈顶的新状态和当前构建的新节点获取到下一个转移状态
                    state = stateStack.top();
                    item = production.left->name;
                    if (lrTable[state].count(item)) {
                        opr = lrTable[state][item];
                        cout << state << " --- " << item << " ---> " << opr << endl;
                        printTrace(nodeStack, stateStack, cout);
                        // 此时是gXX的移进
                        if (opr == "ac") {
                            // 如果规约成了开始符号，会是ac，结束
                            i++; // 原本++的i不用回去了（结束符号不管了）
                            stateStack.pop();
                            cout << "Accepted" << endl << endl;
                            printGTree(node, 0);
                            break;
                        }
                        index = stoi(opr.substr(1, opr.size() - 1));
                        stateStack.push(index);
                        nodeStack.push(node);
                    }
                    else {
                        // 表格中无数据，不符合语法
                        cerr << "Error at index " << i << ": " << endl;
                        cerr << state << " --- " << item << " ---> nothing" << endl;
                        printTrace(nodeStack, stateStack, cerr);
                        return;
                    }
                    break;
                default:
                    // 数据错误
                    cerr << "Error at index " << i << " with token [ " << item
                        << " ] which opr is [ " << opr << " ]" << endl;
                    return;
            }
        }
        else {
            // 可能是注释类token，可以通过判断该token类型是否在语法分析中的终结符集合中来判断
            if (!allEndCharNames.count(item)) {
                ; // 如果该token类型不属于语法分析中的终结符集合，忽略
            }
            else {
                // 如果是文法的类型而表格中无数据，不符合语法，报错
                cerr << "Error at index " << i << ": " << endl;
                cerr << state << " --- " << item << " ---> nothing" << endl;
                printTrace(nodeStack, stateStack, cerr);
                return;
            }
        }
    }
}

/**
 * 根据传入的文法规则和语法树节点栈，从栈中弹出对应数量的语法树节点构建出一个新的语法树节点并返回
 * @param production 文法规则
 * @param stateStack 状态栈，在该函数中没有实际作用，仅将该栈中的状态同步弹出
 * @param nodeStack 语法树栈
 * @return 构建的新语法树节点
 */
GNode Parser::buildGNode(const Production& production, stack<int>& stateStack,
                         stack<GNode>& nodeStack) {
    size_t size = production.right.size();
    cout << production << endl;
    vector<GNode> nodes; // 语法树节点列表
    if (size == 1 && production.right[0]->name == NULL_CHARACTER) {
        // XXX -> .@ 不用弹出，手动存一个节点
        nodes.emplace_back(NULL_CHARACTER, NULL_CHARACTER, vector<GNode>());
    }
    else {
        cout << ">> pop count: " << size << endl;
        while (size--) {
            // 收集节点
            nodes.insert(nodes.begin(), nodeStack.top());
            nodeStack.pop();
            stateStack.pop();
        }
    }
    printTrace(nodeStack, stateStack, cout);
    // 构建语法树节点
    // 根据建点类型执行不同的操作
    const auto buildTypes = production.buildTypes;
    map<int, vector<GNode>> typeToNode; // 记录每种操作的节点数量
    for (size_t i = 0; i < buildTypes.size(); i++) {
        if (!typeToNode.count(buildTypes[i])) typeToNode[buildTypes[i]] = vector<GNode>();
        typeToNode[buildTypes[i]].push_back(nodes[i]);
    }
    if (typeToNode.count(BUILD_TYPE_ROOT) && typeToNode[BUILD_TYPE_ROOT].size() == 1) {
        // 有根节点且只有一个根节点（配置中不允许出现多个根节点）
        auto root = typeToNode[BUILD_TYPE_ROOT][0];
        if (typeToNode.count(BUILD_TYPE_CHILD)) {
            // 有子节点，加入子节点列表
            for (const auto& child : typeToNode[BUILD_TYPE_CHILD]) {
                root.children.push_back(child);
            }
        }
        return root;
    }
    // 没有根节点，则创建节点，名字是规约的左侧非终结符的名字
    auto root = GNode(production.left->name, "", vector<GNode>());
    if (typeToNode.count(BUILD_TYPE_CHILD)) {
        // 有子节点，加入子节点列表
        for (const auto& child : typeToNode[BUILD_TYPE_CHILD]) {
            root.children.push_back(child);
        }
    }
    return root;
}

/**
 * 打印语法树
 * @param node 语法树根节点
 * @param depth 节点深度
 */
// NOLINTNEXTLINE 消除clang-tidy递归警告
void Parser::printGTree(const GNode& node, const int depth) {
    // 要用dfs，bfs的对齐太难了
    // 按深度打印前面的占位
    int temp = depth;
    while (temp--) cout << "|       ";
    cout << "+-------[" << node.name << "]";
    if (!node.value.empty()) cout << ": " << node.value;
    cout << endl;
    // 打印子节点
    for (const auto& child : node.children) {
        printGTree(child, depth + 1);
    }
}
